#include <iostream>
#include <vector>
#include <string>
#include <stdlib.h>
#include <stdlib.h>
#include <boost/filesystem.hpp>
#include "util.hpp"

const std::string src_path = "data/input/"; // html网页数据源路径
const std::string output = "data/output/raw.bin"; // 数据清洗后保存路径

// 获取到的文件，解析其相关属性
struct DocInfo
{
    std::string _title;       // 文档标题
    std::string _content;     // 文档内容
    std::string _url;         // 文档地址
};

// const & : 输入
//       * : 输出
//       & : 输入和输出

// 遍历文件
bool EnumFiles(const std::string& src_path, std::vector<std::string>* file_list)
{
    namespace fs = boost::filesystem;
    fs::path root_path(src_path); // 定义路径对象
    if (!fs::exists(root_path)) {
        std::cerr << src_path << " is not exists" << std::endl;
        return false;
    }

    // 定义对象迭代器对象
    fs::recursive_directory_iterator end;
    for (fs::recursive_directory_iterator iter(root_path); iter != end; iter++)
    {
        if (!fs::is_regular_file(*iter)) {            // 判断是否为普通文件
            continue;
        }
        if (iter->path().extension() != ".html") {    // 判断后缀是否为html
            continue;
        } // 当前的路径一定是一个合法文件路径

        file_list->push_back(iter->path().string());  // 文件路径放到file_list中
    }

    return true;
}
//title
bool ParserTitle(const std::string& file, std::string* title)
{
    size_t begin = file.find("<title>"); // 查找字符串<title>
    if (begin == std::string::npos) {
        std::cout << "beign error" << std::endl;
        return false;
    }
    size_t end = file.find("</title>", begin); // 查找字符串</title>
    if (end == std::string::npos) {
        std::cout << "end error" << std::endl;
        return false;
    }

    begin += std::string("<title>").size(); // 越过字符串，指向标题内容位置
    if (begin > end) {
        std::cout << "begin > end error" << std::endl;
        return false;
    }

    *title = std::string(file, begin, end - begin); // 标题内容[begin, end]

    return true;
}

// content
bool ParserContent(const std::string& file, std::string* content)
{
    //去标签，基于一个简易的状态机编写
    enum STATUS {
        LABLE,
        CONTENT
    };
    enum STATUS s = LABLE;
    for (char c : file)
    {
        switch (s)
        {
        case LABLE:
            if (c == '>') s = CONTENT;   // 可能进入读内容模式
            break;
        case CONTENT:
            if (c == '<') s = LABLE;     // 可能进入读标签模式
            else {
                // 处理掉原始内容中的\n，将其留作html解析之后的文本分隔符
                if (c == '\n') c = '\0';
                content->push_back(c);   //
            }
            break;
        default:
            std::cout << "unkown status" << std::endl;
            break;
        }
    }

    return true;
}
// url
bool ParserUrl(const std::string& file, std::string* url)
{
    // https://www.boost.org/doc/libs/1_80_0/doc/html/*
    // $(project_dir)/data/input/*
    std::string url_head = "https://www.boost.org/doc/libs/1_80_0/doc/html/"; // 构建前缀

    std::string url_tail = file.substr(src_path.size());
    if (url_tail.size() == 0) {
        std::cout << "file suffix find error" << std::endl;
        return false;
    }
    *url = url_head + url_tail;

    return true;
}


// 解析文件
bool ParserFiles(const std::vector<std::string>& file_list, std::vector<DocInfo>* parser_res)
{
    for (auto& file : file_list)
    {
        //读取文件
        std::string result; // 读取的结果
        if (!Util::ReadFile(file, &result)) {
            continue;
        }
        // 解析文件
        DocInfo info;
        // title
        // <title>Redirect to generated documentation</title>
        if (!ParserTitle(result, &info._title)) {
            continue;
        }
        // content
        if (!ParserContent(result, &info._content)) {
            continue;
        }
        // url
        if (!ParserUrl(file, &info._url)) {
            continue;
        }

        // 当前文档解析完毕，属性在info中，导入parser_res
        parser_res->push_back(std::move(info)); // 内存迁移，高效
    }

    return true;
}

// 保存文件
bool SaveFiles(const std::vector<DocInfo>& parser_res, const std::string& output)
{
#define SEP '\3'
    std::ofstream ofs(output, std::ios::out | std::ios::binary); // 以二进制形式写入
    if (!ofs.is_open()) {
        std::cerr << "open " << output << " failed" << std::endl;
        return false;
    }
    // 遍历数据
    for (auto& e : parser_res)
    {
        std::string out_string(e._title + SEP + e._content + SEP + e._url + '\n');
        ofs.write(out_string.c_str(), out_string.size()); //写入文件
    }
    ofs.close();

    return true;
}

//Debug Test
void showInfo(std::vector<DocInfo> parser_res)
{
    for (auto e : parser_res) {
        std::cout << "title: " << e._title << std::endl;
        std::cout << "content: " << e._content << std::endl;
        std::cout << "url: " << e._url << std::endl;
    }

}

int main()
{
    std::vector<std::string> file_list; // 保存所有文件名

    // 递归遍历所有数据源文件，将文件名保存到file_list中，以便后期读取
    if (!EnumFiles(src_path, &file_list)) {
        std::cerr << "enum file error" << std::endl;
        exit(1);
    }
    std::cerr << "enum file success" << std::endl;

    // 读取每个文件的内容，并进行解析
    std::vector<DocInfo> parser_res;
    if (!ParserFiles(file_list, &parser_res)) {
        std::cerr << "parser file error" << std::endl;
        exit(2);
    }
    std::cerr << "parser file success" << std::endl;

    // 把解析得到的内容写入到output中，以\3作为每个文档内容的分隔符
    if (!SaveFiles(parser_res, output)) {
        std::cerr << "save file error" << std::endl;
        exit(3);
    }
    std::cerr << "save file success" << std::endl;


    return 0;
}
